import { defineStore } from "pinia";
import { pinia } from "..";
import { GlobalStoreEnum } from "../enum";
import { AclType, IAclState, IMenu, Tags } from "../interface";
import { getHash } from "../util/store.util";

export const useAcl = defineStore(GlobalStoreEnum.ACL, {
  state: (): IAclState => ({
    full: false,
    roles: [],
    points: []
  }),
  getters: {
    data(state) {
      return state;
    }
  },
  actions: {
    setFull(val: boolean) {
      this.full = val;
    },
    /**
     * 设置当前用户权限能力（会先清除所有）
     */
    setAbility(abilities: string[]) {
      this.points = abilities || [];
    },
    /**
     * 设置当前用户角色（会先清除所有）
     */
    setRole(roles: string[]) {
      this.roles = roles;
    },

    getMenuAcl(code: string, router?: string, noHash = false) {
      const path = router ? router : noHash ? "" : getHash();
      return `${path}:${code}`;
    },

    /**
     * 根据权限点获取当前页面的权限数组
     *
     * @param arg 权限点数组
     * @returns
     */
    getAclArray(...arg: string[]) {
      return arg.map(a => {
        return this.getMenuAcl(a);
      });
    },

    getAclPath() {
      return this.points?.[0]?.split(":")[0];
    },

    getRouter(menu: IMenu | Tags) {
      return menu.moda === "LINK"
        ? menu.link
        : menu.moda === "ROUTER"
        ? menu.router
        : menu.frame;
    },

    hasMenuAcl(code: string, router?: string) {
      if (this.full) {
        return true;
      }
      const point = this.getMenuAcl(code, router);
      return this.points.includes(point);
    },

    /**
     * 当前用户是否有对应权限点
     */
    canAbility(value: AclType) {
      return this.can(value);
    },

    can(value: AclType) {
      if (!value) {
        return true;
      }
      const {
        except = false,
        mode = "allOf",
        points = [],
        roles = []
      } = value || ({} as AclType);
      let roleOk = true;
      let pointsOk = true;
      if (this.full) {
        return true;
      }
      if (roles.length) {
        roleOk = roles?.[mode === "allOf" ? "every" : "some"](r =>
          this.roles.includes(r)
        );
      }
      if (points.length) {
        pointsOk = points?.[mode === "allOf" ? "every" : "some"](r =>
          this.points.includes(r)
        );
      }
      const result =
        mode === "allOf"
          ? roleOk && pointsOk
          : (roles.length && roleOk) || (points.length && pointsOk);

      return except === true ? !result : result;
    }
  }
});

export const useAclHooks = () => {
  return useAcl(pinia);
};
